package cn.itsource.ymcc.service.impl;

import cn.itsource.ymcc.client.ESCourseFeignClient;
import cn.itsource.ymcc.client.MediaFeignClient;
import cn.itsource.ymcc.constants.BaseConstants;
import cn.itsource.ymcc.context.LoginContext;
import cn.itsource.ymcc.doc.CourseDoc;
import cn.itsource.ymcc.domain.*;
import cn.itsource.ymcc.dto.CourseAddDto;
import cn.itsource.ymcc.dto.CourseDetailDto;
import cn.itsource.ymcc.dto.CourseInfoDto;
import cn.itsource.ymcc.mapper.*;
import cn.itsource.ymcc.mq.CourseMessageSender;
import cn.itsource.ymcc.result.JSONResult;
import cn.itsource.ymcc.service.ICourseChapterService;
import cn.itsource.ymcc.service.ICourseService;
import cn.itsource.ymcc.service.ITeacherService;
import cn.itsource.ymcc.util.AssertUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author whale
 * @since 2021-09-13
 */
//@Service
//@Transactional
@Slf4j
public class CourseServiceImpl2 extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    @Autowired
    private ITeacherService teacherService;
    @Autowired
    private ICourseChapterService courseChapterService ;
    @Autowired
    private MediaFeignClient mediaFeignClient;
    @Autowired
    private CourseDetailMapper courseDetailMapper;
    @Autowired
    private CourseMarketMapper courseMarketMapper;
    @Autowired
    private ESCourseFeignClient courseFeignClient;
    @Autowired
    private CourseMessageSender courseMessageSender;
    @Autowired
    private CourseTypeMapper courseTypeMapper;
    @Autowired
    private CourseResourceMapper courseResourceMapper;
    @Autowired
    private CourseTeacherMapper courseTeacherMapper;

    public CourseDetailDto selectDetailData(Long id) {

        AssertUtil.isNotNull(id,"无效的课程ID");

        CourseDetailDto result = new CourseDetailDto();

        //媒体数据======================================================================================================================
        //媒体数据必须同步，否则Token转发失败
        List<MediaFile> mediaFiles = getMediaInfo(id);

        //课程数据======================================================================================================================
        CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> getCourseInfo(id, result)).thenAccept(courseChapters -> {
            //处理课程和媒体数据的关系=======================================================================================================
            handleMediaInfo(courseChapters, mediaFiles);
        });

        try {
            completableFuture.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        log.info("获取课程详细信息 {}",result);
        return result;
    }

    //处理课程章节和媒体数据的关系
    private void handleMediaInfo(List<CourseChapter> courseChapters, List<MediaFile> mediaFiles) {
        mediaFiles = mediaFiles.stream().map(mediaFile -> {
            //清空URL,用户没购买课程，但是可以展示出课程的章节列表
            mediaFile.setFileUrl(null);
            return mediaFile;
        }).collect(Collectors.toList());

        //章节
        Map<Long, CourseChapter> courseChapterMap = courseChapters.stream().collect(Collectors.toMap(CourseChapter::getId, CourseChapter -> CourseChapter));

        //媒体文件添加到章节
        mediaFiles.forEach(mediaFile -> {
            CourseChapter courseChapter = courseChapterMap.get(mediaFile.getChapterId());
            if (courseChapter != null) {
                courseChapter.getMediaFiles().add(mediaFile);
            }
        });
    }
   //远程获取媒体数据
    private List<MediaFile> getMediaInfo(Long id) {
        //4.远程获取视频列表
        JSONResult jsonResult = mediaFeignClient.selectByCourseId(id);

        AssertUtil.isTrue(jsonResult.isSuccess(), "课程章节获取失败");
        AssertUtil.isNotNull(jsonResult.getData(), "课程章节获取失败");

        //获取视频列表
        return JSON.parseArray(jsonResult.getData().toString(), MediaFile.class);
    }

    //获取课程数据
    private List<CourseChapter> getCourseInfo(Long id, CourseDetailDto result) {
        //1.查询课程
        Course course = baseMapper.selectById(id);
        AssertUtil.isNotNull(course,"无效的课程");
        AssertUtil.isEquals(course.getStatus(),Course.STATUS_ONLINE , "课程没有上线");

        Wrapper<CourseDetail> wrapper = new EntityWrapper<>();
        wrapper.eq("id",id);
        CourseDetail courseDetail = courseDetailMapper.selectList(wrapper).get(0);
        result.setCourseDetail(courseDetail);

        //2.查询教师
        List<Teacher> teachers = teacherService.selectByCourseId(id);
        result.setTeachers(teachers);

        //3.查询章节
        Wrapper<CourseChapter> chapterQuery = new EntityWrapper<>();
        chapterQuery.eq("course_id",id);
        List<CourseChapter> courseChapters = courseChapterService.selectList(chapterQuery);

        result.setCourseChapters(courseChapters);
        result.setCourse(course);

        CourseMarket courseMarket = courseMarketMapper.selectById(id);
        result.setCourseMarket(courseMarket);
        return courseChapters;
    }

    public CourseDetailDto selectDetailData2(Long id) {

        AssertUtil.isNotNull(id,"无效的课程ID");

        CourseDetailDto result = new CourseDetailDto();

        //课程数据========================================================================================
        //1.查询课程
        List<CourseChapter> courseChapters = getCourseInfo(id, result);

        //媒体数据========================================================================================
        List<MediaFile> mediaFiles = getMediaInfo(id);

       //处理课程章节和媒体的关系
        handleMediaInfo(courseChapters,mediaFiles);

        return result;
    }

    @Override
    public CourseInfoDto selectCourseInfoById(Long id) {
        Course course = baseMapper.selectById(id);
        CourseMarket courseMarket = courseMarketMapper.selectById(id);
        return new CourseInfoDto(course , courseMarket);
    }




    /**-----------------------------------------------------------------
     * Description：课程发布
     * 1.判断参数
     * 2.判断课程状态必须是下线状态
     * 3.修改课程状态为：上线状态
     * 4.调用Feign保存课程到ES中
     * 5.消息推送
     *-----------------------------------------------------------------*/
    @Override
    @Transactional
    public void onLineCourse(Long id) {
        //* 1.判断参数
        AssertUtil.isNotNull(id,"无效的参数，刷新重试" );

        //* 2.判断课程状态必须是下线状态
        Course course = super.selectById(id);
        AssertUtil.isNotNull(course,"无效的课程，请重试" );
        AssertUtil.isTrue(course.getStatus() == BaseConstants.CourseConstants.STATUS_OFF_LIINE,
                "课程状态异常");

        //* 3.修改课程状态为：上线状态
        course.setStatus(BaseConstants.CourseConstants.STATUS_ON_LIINE);
        Date date = new Date();
        course.setOnLineTime(date);


        //* 4.调用Feign保存课程到ES中
        CourseMarket market = courseMarketMapper.selectById(id);

        CourseDoc doc = new CourseDoc();
        BeanUtils.copyProperties(market, doc);
        BeanUtils.copyProperties(course, doc);
        //处理价格
        doc.setPrice(market.getPrice().doubleValue());
        doc.setPriceOld(market.getPriceOld().doubleValue());
        doc.setChargeName(market.getCharge() == 0 ?"免费":"收费");
        //老师
        List<Teacher> teachers = teacherService.selectByCourseId(id);

        List<String> teacherNames = teachers.stream().map(teacher -> teacher.getName()).collect(Collectors.toList());
        String joinTeacherNames = StringUtils.join(teacherNames.toArray(), " . ");
        doc.setTeacherName(joinTeacherNames);

        JSONResult jsonResult = courseFeignClient.addCourse(doc);
        AssertUtil.isTrue(jsonResult.isSuccess(), "课程添加到ES失败");

        super.updateById(course);

        //推送消息
        try{
            courseMessageSender.publishMessage(course);
        }catch (Exception e){
            e.printStackTrace();
            log.info("消息推送失败");
            //TODO
            //throw new GlobleException("消息推送失败");
        }

    }

    /**-----------------------------------------------------------------
     * Description： 保存课程
     * 1.判断参数
     * 2.判断重复
     * 3.保存课程
     * 4.保存详情，设置课程ID作为详情ID
     * 5.保存营销，设置课程ID作为详情ID
     * 6.给选择的课程分类的课程数量+1
     *-----------------------------------------------------------------*/
    @Override
    public void save(CourseAddDto dto) {

        //* 1.判断参数
        Course course = dto.getCourse();
        CourseDetail courseDetail = dto.getCourseDetail();
        CourseMarket courseMarket = dto.getCourseMarket();

        AssertUtil.isNotEmpty(course.getName(),"课程名不可为空" );
        //* 2.判断重复，省略..

        //* 3.保存课程
        course.setStatus(BaseConstants.CourseConstants.STATUS_OFF_LIINE);

        //获取登录信息
        Login login = LoginContext.getLogin();
        AssertUtil.isNotNull(login,"请登录");

        course.setLoginId(login.getId());
        course.setLoginUserName(login.getUsername());

        List<String> teacharNames = teacherService.selectBatchIds(dto.getTeacharIds()).stream().map(t -> t.getName()).collect(Collectors.toList());
        String teacharNameStr = StringUtils.join(teacharNames.toArray(), ",");
        course.setTeacherNames(teacharNameStr);
        super.insert(course);

        //* 4.保存详情，设置课程ID作为详情ID
        courseDetail.setId(course.getId());
        courseDetailMapper.insert(courseDetail);

        //* 5.保存营销，设置课程ID作为详情ID
        courseMarket.setId(course.getId());
        courseMarketMapper.insert(courseMarket );

        //* 6.给选择的课程分类的课程数量+1
        CourseType courseType = courseTypeMapper.selectById(course.getCourseTypeId());
        courseType.setTotalCount(courseType.getTotalCount()+1);
        courseTypeMapper.updateById(courseType);

        //保存课件
        CourseResource courseResource = dto.getCourseResource();
        courseResource.setCourseId(course.getId());
        courseResourceMapper.insert(dto.getCourseResource());

        //保存老师
        List<Long> teacharIds = dto.getTeacharIds();
        if(teacharIds != null && !teacharIds.isEmpty()){
            teacharIds.forEach(teacharId->{
                courseTeacherMapper.insert(new CourseTeacher(null,teacharId,course.getId()));
            });
        }
    }

    @Override
    public List<CourseInfoDto> selectCourseInfosById(List<Long> courseIds) {
        List<CourseInfoDto> result = new ArrayList<>(courseIds.size());
        courseIds.forEach(id->{
            Course course = baseMapper.selectById(id);
            CourseMarket courseMarket = courseMarketMapper.selectById(id);
            result.add(new CourseInfoDto(course , courseMarket));
        });
        return result;
    }



}
